package com.jzo2o.customer.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jzo2o.api.customer.dto.response.AddressBookResDTO;
import com.jzo2o.api.publics.MapApi;
import com.jzo2o.api.publics.dto.response.LocationResDTO;
import com.jzo2o.common.expcetions.ForbiddenOperationException;
import com.jzo2o.common.model.PageResult;
import com.jzo2o.common.utils.BeanUtils;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.NumberUtils;
import com.jzo2o.common.utils.StringUtils;
import com.jzo2o.customer.mapper.AddressBookMapper;
import com.jzo2o.customer.model.domain.AddressBook;
import com.jzo2o.customer.model.dto.request.AddressBookPageQueryReqDTO;
import com.jzo2o.customer.model.dto.request.AddressBookUpsertReqDTO;
import com.jzo2o.customer.service.IAddressBookService;
import com.jzo2o.mvc.utils.UserContext;
import com.jzo2o.mysql.utils.PageUtils;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 地址薄 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2023-07-06
 */
@Service
public class AddressBookServiceImpl extends ServiceImpl<AddressBookMapper, AddressBook> implements IAddressBookService {
    @Resource
    private AddressBookMapper addressBookMapper;
    @Resource
    private MapApi mapApi;


    /**
     * 设置默认地址
     *
     * @param id   地址簿id
     * @param flag 是否为默认状态
     */
    @Override
    @Transactional
    public void updateDefaultStatuss(Long id, Integer flag) {
        Long userId = UserContext.currentUserId();
        // 验证地址是否属于当前用户
        AddressBook address = this.lambdaQuery()
                .eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getId, id)
                .one();

        if (address == null) {
            throw new ForbiddenOperationException("地址不存在或不属于当前用户");
        }
        if (flag == 1) {
            // 1. 先将该用户所有地址设为非默认
            this.lambdaUpdate()
                    .eq(AddressBook::getUserId, userId)
                    .set(AddressBook::getIsDefault, 0)
                    .update();
            // 2. 再将当前地址设为默认
            this.lambdaUpdate()
                    .eq(AddressBook::getUserId, userId)
                    .eq(AddressBook::getId, id)
                    .set(AddressBook::getIsDefault, 1)
                    .update();
        } else {
            // 取消默认状态
            this.lambdaUpdate()
                    .eq(AddressBook::getUserId, userId)
                    .eq(AddressBook::getId, id)
                    .set(AddressBook::getIsDefault, 0)
                    .update();
        }
    }

    /**
     * 删除地址簿
     *
     * @param ids 地址簿id列表
     */
    @Override
    public void deleteAddress(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            System.out.println("传入的ids集合为空，不执行删除操作");
            return;
        }
        baseMapper.deleteBatchIds(ids);
    }

    /**
     * 修改地址簿
     *
     * @param id  地址簿id
     * @param dto 传入的参数
     */
    @Override
    public void putAddress(Long id, AddressBookUpsertReqDTO dto) {
        Long userId = UserContext.currentUserId();
        //拿到当前用户的所有地址簿
        List<AddressBook> list = this.lambdaQuery().eq(AddressBook::getUserId, userId)
                .list();
        if (CollUtils.isEmpty(list)) {
            throw new ForbiddenOperationException("当前用户无地址簿");
        }
        for (AddressBook addressBook : list) {
            //查看修改的那个地址簿对象
            if (addressBook.getId().equals(id)) {
                //在判断当前修改的状态是否为默认地址，如果是将其他的地址设为空
                if (dto.getIsDefault() == 1) {
                    // 批量更新，效率更高
                    this.lambdaUpdate()
                            .eq(AddressBook::getUserId, userId)
                            // 排除当前要修改的地址
                            .ne(AddressBook::getId, id)
                            .set(AddressBook::getIsDefault, 0)
                            .update();
                }
                //判断是否有经纬度，如果没有通过地址详情查找经纬度
                String[] split = mapApi.getLocationByAddress(dto.getAddress()).getLocation().split(",");
                if (ObjectUtil.isEmpty(split) || split.length != 2) {
                    throw new ForbiddenOperationException("查询无此经纬度");
                }
                AddressBook addressBook1 = BeanUtil.copyProperties(dto, AddressBook.class);
                addressBook1.setLat(Double.parseDouble(split[0]));
                addressBook1.setLon(Double.parseDouble(split[1]));
                addressBook1.setId(id);
                addressBook1.setUserId(userId);
                addressBookMapper.updateById(addressBook1);
            }
        }
    }

    /**
     * 根据地址id查询地址详细信息
     *
     * @param id 地址簿id
     * @return 返回封装结果
     */
    @Override
    public AddressBookResDTO getAddress(Long id) {
        AddressBook addressBook = baseMapper.selectById(id);
        AddressBookResDTO addressBookResDTO = BeanUtils.copyProperties(addressBook, AddressBookResDTO.class);
        return addressBookResDTO;
    }

    /**
     * 分页查询地址簿信息
     *
     * @param dto 传来的参数
     * @return 返回封装结果
     */
    @Override
    public PageResult<AddressBookResDTO> pageRequest(AddressBookPageQueryReqDTO dto) {
        //1．构建page对象,传入参数:1．查询对象（主要是pageNo和pageSize））2．查询对象对应的实体类
        Page<AddressBook> page = PageUtils.parsePageQuery(dto, AddressBook.class);
        //2．调用查询方法，传入参数：1．page对象2．查询条件封装器
        Long userId = UserContext.currentUserId();
        QueryWrapper<AddressBook> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId);
        Page<AddressBook> addressBookPage = baseMapper.selectPage(page, wrapper);
        //3．查询结果转换为PageResult
        return PageUtils.toPage(addressBookPage, AddressBookResDTO.class);

    }

    /**
     * 地址簿新增
     *
     * @param addressBookUpsertReqDTO 传来的参数
     */
    @Override
    public void addAddress(AddressBookUpsertReqDTO addressBookUpsertReqDTO) {
        //获取当前用户的id
        Long userId = UserContext.currentUserId();
        List<AddressBook> list = this.lambdaQuery().eq(AddressBook::getUserId, userId).list();
        if (ObjectUtil.isEmpty(list)) {
            throw new ForbiddenOperationException("查询无任何地址详情");
        }
        for (AddressBook addressBook : list) {
            //判断当前是否有存在的默认地址
            if (addressBook.getIsDefault() == 1) {
                addressBook.setIsDefault(0);
                baseMapper.updateById(addressBook);
            }
        }
        //2．如果前端没有传递经纬度，则需要根据传递的详细地址调用高德地图获取经纬度 (相关接口已经提供)
        LocationResDTO locationByAddress = mapApi.getLocationByAddress(addressBookUpsertReqDTO.getAddress());
        String location = locationByAddress.getLocation();
        //将这个根据逗号进行分割
        String[] split = location.split(",");
        double lon = Double.parseDouble(split[0]);
        double lat = Double.parseDouble(split[1]);
        AddressBook addressBook = BeanUtils.copyProperties(addressBookUpsertReqDTO, AddressBook.class);
        addressBook.setLat(lat);
        addressBook.setLon(lon);
        addressBook.setUserId(userId);
        baseMapper.insert(addressBook);
    }

    /**
     * 查询用户默认地址值
     *
     * @return 用户默认地址
     */
    @Override
    public AddressBookResDTO findDefaultAddress() {
        //获取当前用户的id
        Long userId = UserContext.currentUserId();
        AddressBook addressBook = this.lambdaQuery().eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getIsDefault, 1)
                .one();
        if (ObjectUtil.isNull(addressBook)) {
            throw new ForbiddenOperationException("查询地址簿对象");
        }
        AddressBookResDTO addressBookResDTO = BeanUtil.copyProperties(addressBook, AddressBookResDTO.class);
        return addressBookResDTO;
    }

    /**
     * 地址薄新增
     *
     * @param addressBookUpsertReqDTO 插入更新地址薄
     */
    @Override
    public void add(AddressBookUpsertReqDTO addressBookUpsertReqDTO) {
        //当前用户id
        Long userId = UserContext.currentUserId();
        //如果新增地址设为默认，取消其他默认地址
        if (1 == addressBookUpsertReqDTO.getIsDefault()) {
            cancelDefault(userId);
        }

        AddressBook addressBook = BeanUtil.toBean(addressBookUpsertReqDTO, AddressBook.class);
        addressBook.setUserId(userId);

        //组装详细地址
        String completeAddress = addressBookUpsertReqDTO.getProvince() +
                addressBookUpsertReqDTO.getCity() +
                addressBookUpsertReqDTO.getCounty() +
                addressBookUpsertReqDTO.getAddress();

        //如果请求体中没有经纬度，需要调用第三方api根据详细地址获取经纬度
        if (ObjectUtil.isEmpty(addressBookUpsertReqDTO.getLocation())) {
            //远程请求高德获取经纬度
            LocationResDTO locationDto = mapApi.getLocationByAddress(completeAddress);
            //经纬度(字符串格式：经度,纬度),经度在前，纬度在后
            String location = locationDto.getLocation();
            addressBookUpsertReqDTO.setLocation(location);
        }

        if (StringUtils.isNotEmpty(addressBookUpsertReqDTO.getLocation())) {
            // 经度
            addressBook.setLon(NumberUtils.parseDouble(addressBookUpsertReqDTO.getLocation().split(",")[0]));
            // 纬度
            addressBook.setLat(NumberUtils.parseDouble(addressBookUpsertReqDTO.getLocation().split(",")[1]));
        }
        addressBookMapper.insert(addressBook);
    }

    /**
     * 地址薄修改
     *
     * @param id                      地址薄id
     * @param addressBookUpsertReqDTO 插入更新地址薄
     */
    @Override
    @Transactional
    public void update(Long id, AddressBookUpsertReqDTO addressBookUpsertReqDTO) {
        if (1 == addressBookUpsertReqDTO.getIsDefault()) {
            cancelDefault(UserContext.currentUserId());
        }

        AddressBook addressBook = BeanUtil.toBean(addressBookUpsertReqDTO, AddressBook.class);
        addressBook.setId(id);

        //调用第三方，根据地址获取经纬度坐标
        String completeAddress = addressBookUpsertReqDTO.getProvince() +
                addressBookUpsertReqDTO.getCity() +
                addressBookUpsertReqDTO.getCounty() +
                addressBookUpsertReqDTO.getAddress();
        //远程请求高德获取经纬度
        LocationResDTO locationDto = mapApi.getLocationByAddress(completeAddress);
        //经纬度(字符串格式：经度,纬度),经度在前，纬度在后
        String location = locationDto.getLocation();
        if (StringUtils.isNotEmpty(location)) {
            // 经度
            addressBook.setLon(NumberUtils.parseDouble(locationDto.getLocation().split(",")[0]));
            // 纬度
            addressBook.setLat(NumberUtils.parseDouble(locationDto.getLocation().split(",")[1]));
        }
        addressBookMapper.updateById(addressBook);
    }

    /**
     * 取消默认
     *
     * @param userId 用户id
     */
    private void cancelDefault(Long userId) {
        LambdaUpdateWrapper<AddressBook> updateWrapper = Wrappers.<AddressBook>lambdaUpdate()
                .eq(AddressBook::getUserId, userId)
                .set(AddressBook::getIsDefault, 0);
        super.update(updateWrapper);
    }

    /**
     * 地址薄设为默认/取消默认
     *
     * @param userId 用户id
     * @param id     地址薄id
     * @param flag   是否为默认地址，0：否，1：是
     */
    @Override
    public void updateDefaultStatus(Long userId, Long id, Integer flag) {
        if (1 == flag) {
            //如果设默认地址，先把其他地址取消默认
            cancelDefault(userId);
        }

        AddressBook addressBook = new AddressBook();
        addressBook.setId(id);
        addressBook.setIsDefault(flag);
        addressBookMapper.updateById(addressBook);
    }

    /**
     * 分页查询
     *
     * @param addressBookPageQueryReqDTO 查询条件
     * @return 分页结果
     */
    @Override
    public PageResult<AddressBookResDTO> page(AddressBookPageQueryReqDTO addressBookPageQueryReqDTO) {
        Page<AddressBook> page = PageUtils.parsePageQuery(addressBookPageQueryReqDTO, AddressBook.class);

        LambdaQueryWrapper<AddressBook> queryWrapper = Wrappers.<AddressBook>lambdaQuery().eq(AddressBook::getUserId, UserContext.currentUserId());
        Page<AddressBook> serveTypePage = addressBookMapper.selectPage(page, queryWrapper);
        return PageUtils.toPage(serveTypePage, AddressBookResDTO.class);
    }

    /**
     * 获取默认地址
     *
     * @return 默认地址
     */
    @Override
    public AddressBookResDTO defaultAddress() {
        LambdaQueryWrapper<AddressBook> queryWrapper = Wrappers.<AddressBook>lambdaQuery()
                .eq(AddressBook::getUserId, UserContext.currentUserId())
                .eq(AddressBook::getIsDefault, 1);
        AddressBook addressBook = addressBookMapper.selectOne(queryWrapper);
        return BeanUtil.toBean(addressBook, AddressBookResDTO.class);
    }

    @Override
    public List<AddressBookResDTO> getByUserIdAndCity(Long userId, String city) {

        List<AddressBook> addressBooks = lambdaQuery()
                .eq(AddressBook::getUserId, userId)
                .eq(AddressBook::getCity, city)
                .list();
        if (CollUtils.isEmpty(addressBooks)) {
            return new ArrayList<>();
        }
        return BeanUtils.copyToList(addressBooks, AddressBookResDTO.class);
    }
}
